package ca.etsmtl.log430.lab2;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Observable;

import ca.etsmtl.log430.common.Menus;
import ca.etsmtl.log430.common.Project;
import ca.etsmtl.log430.common.ProjectList;
import ca.etsmtl.log430.common.Resource;

/**
 * Assigns resources to projects.
 *  
 * @author A.J. Lattanze, CMU
 * @version 1.5, 2013-Oct-06
 */

/*
 * Modification Log **********************************************************
 * v1.5, R. Champagne, 2013-Oct-06 - Various refactorings for new lab.
 * 
 * v1.4, R. Champagne, 2012-Jun-19 - Various refactorings for new lab.
 * 
 * v1.3, R. Champagne, 2012-Feb-14 - Various refactorings for new lab.
 * 
 * v1.2, R. Champagne, 2011-Feb-24 - Various refactorings, conversion of
 * comments to javadoc format.
 * 
 * v1.1, R. Champagne, 2002-Jun-19 - Adapted for use at ETS.
 * 
 * v1.0, A.J. Lattanze, 12/29/99 - Original version.
 * ***************************************************************************
 */
public class AssignResourceToProject extends Communication
{
	public AssignResourceToProject(Integer registrationNumber, String componentName) {
		super(registrationNumber, componentName);
	}

	/**
	 * The update() method is an abstract method that is called whenever the
	 * notifyObservers() method is called by the Observable class. First we
	 * check to see if the NotificationNumber is equal to this thread's
	 * RegistrationNumber. If it is, then we execute.
	 * 
	 * @see ca.etsmtl.log430.lab2.Communication#update(java.util.Observable,
	 *      java.lang.Object)
	 */
	public void update(Observable thing, Object notificationNumber) {
		Menus menu = new Menus();
		Resource myResource = new Resource();
		Project myProject = new Project();

		try{
			if (registrationNumber.compareTo((Integer)notificationNumber) == 0) {
				addToReceiverList("ListResourcesComponent");
				addToReceiverList("ListProjectsComponent");

				// Display the resources and prompt the user to pick one

				signalReceivers("ListResourcesComponent");

				myResource = menu.pickResource(CommonData.theListOfResources.getListOfResources());

				if (myResource != null) {
					/*
					 * Display the projects that are available and ask the user to
					 * pick one
					 */
					signalReceivers("ListProjectsComponent");

					myProject = menu.pickProject(CommonData.theListOfProjects.getListOfProjects());

					if (myProject != null)	{	

						updateProjectList(myResource, CommonData.theListOfProjects.getListOfProjects());

						if(checkDateConflict(myProject, myResource)){
							/*
							 * If the selected project and resource exist, then complete
							 * the assignment process.
							 */
							myProject.assignResource(myResource);
							myResource.assignProject(myProject);
							
							System.out.println ("\n\n *** Project was assigned successfully ***");
						}else{
							throw new Exception();
						}

					} else {
						System.out.println("\n\n *** Project not found ***");
					} 
				} else {
					System.out.println("\n\n *** Resource not found ***");
				}
			}
		}catch(Exception e){
			String message = e.getMessage() != null ? e.getMessage() : "Error - Assigning project to overloaded resource";
			//System.out.println("Error - Assigning project to overloaded resource");
			System.out.println(message);
			myProject = null;
		}
	}
	/**
	 * Methods that allows to update the previous list of projects 
	 * @param resource
	 * @param pList
	 */
	public static void updateProjectList(Resource resource, ProjectList pList){

		resource.getPreviouslyAssignedProjectList().goToFrontOfList();

		Project project = resource.getPreviouslyAssignedProjectList().getNextProject();

		while(project != null){
			Project tmp = pList.findProjectByID(project.getID());

			if (tmp != null){
				project.setProjectName(tmp.getProjectName());
				project.setStartDate(tmp.getStartDate());
				project.setEndDate(tmp.getEndDate());
				project.setPriority(tmp.getPriority());
			}
			project = resource.getPreviouslyAssignedProjectList().getNextProject();
		}
	}

	/**
	 * CheckDateConflict allows the user to determine with a project and a resource if there is any conflicts
	 * either with dates or priority. The method will return a boolean indicating if there is a one or not. 
	 * In the case there is a error message will be shown to the console indicating what is wrong.
	 * 
	 * @param project
	 * @param resource
	 * @return
	 * @throws Exception
	 */
	public static boolean checkDateConflict(Project project,Resource resource) throws Exception{

		ProjectList pListCurrent = new ProjectList();
		ProjectList pListPrevious = new ProjectList();
		ProjectList pNewCurrentList = new ProjectList();


		resource.getPreviouslyAssignedProjectList().goToFrontOfList();
		resource.getProjectsAssigned().goToFrontOfList();

		pListCurrent = resource.getProjectsAssigned();
		pListPrevious = resource.getPreviouslyAssignedProjectList();

		Project p = resource.getPreviouslyAssignedProjectList().getNextProject();
		Project q = resource.getProjectsAssigned().getNextProject();

		//Current assigned projects
		while (q != null)
		{
			pNewCurrentList.addProject(q);
			q = pListCurrent.getNextProject();
		}

		//Previously assigned projects
		while (p != null)
		{	
			pNewCurrentList.addProject(p);
			p = pListPrevious.getNextProject();
		}

		pNewCurrentList.goToFrontOfList();
		Project r = pNewCurrentList.getNextProject();
		int cpt = 0;

		while(r != null)
		{
			//(StartA <= EndB) and (EndA >= StartB)
			if (!project.getID().equals(r.getID())){
				if (sToDateConv(r.getStartDate()).before(sToDateConv(project.getEndDate())) && sToDateConv(r.getEndDate()).after(sToDateConv(project.getStartDate())))
				{
					if(r.getPriority().equals("H"))
					{
						cpt += 100;
						//throw new Exception("Project overlap already a High Priority Project");
					}
					else if (r.getPriority().equals("L"))
					{
						cpt += 25;
					}
					else if (r.getPriority().equals("M"))
					{
						cpt += 50;
					}
					else 
					{
						throw new Exception("Error in Priority case !!!!! ");
					}
				}
			}else{
				throw new Exception("Project already assigned");
			}	
			r = pNewCurrentList.getNextProject();
		} 
		int projectprio = 0;
		if (project.getPriority().equals("H"))
			projectprio=100;
		else if(project.getPriority().equals("L"))
			projectprio=25;
		else if(project.getPriority().equals("M"))
			projectprio=50;

		if (cpt + projectprio > 100)
		{
			return false;
		}else{
			return true;
		}
	}

	/**
	 * sToDateConv allows the user to transform a string to a formated one and return an Object Date
	 * This allows to manipulate easier the date instance to make different calculation to validate if
	 * ranges of date conincide or are out of bound.
	 * 
	 * @param stringDate
	 * @return
	 */
	public static Date sToDateConv(String stringDate){

		DateFormat formatter;
		Date date = new Date();
		formatter = new SimpleDateFormat("yyyy-MM-dd");
		try {
			date = (Date) formatter.parse(stringDate);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return date;
	}
}